﻿// <copyright file="IPAddressInspector.cs" company="SharpSTS">
// Copyright (c) 2007, 2008 All Right Reserved, http://sharpsts.com/
//
// This source is subject to the Microsoft Permissive License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Barry Dorrans</author>
// <email>barryd@idunno.org</email>
// <date>2008-06-13</date>
// <summary>Provides a custom message inspector to check the IP address of the caller against a list of allowed IP addresses.</summary>

namespace SharpSTS.CardControl
{
    using System.Net;
    using System.Security;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;

    /// <summary>
    /// Inspects inbound messages and authorises the source IP address.
    /// </summary>
    internal class IPAddressInspector : IDispatchMessageInspector
    {
        /// <summary>
        /// Called after an inbound message has been received but before the message is dispatched to the intended operation.
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="channel">The incoming channel.</param>
        /// <param name="instanceContext">The current service instance.</param>
        /// <returns>
        /// The object used to correlate state. This object is passed back in the <see cref="M:System.ServiceModel.Dispatcher.IDispatchMessageInspector.BeforeSendReply(System.ServiceModel.Channels.Message@,System.Object)"/> method.
        /// </returns>
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            MessageProperties messageProperties = request.Properties;

            RemoteEndpointMessageProperty endpointProperty =
              messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

            if (null == endpointProperty || string.IsNullOrEmpty(endpointProperty.Address))
            {
                throw new CommunicationException("Cannot get client IP address");
            }

            IPAddress callingIPAddress = IPAddress.Parse(endpointProperty.Address);

            if (!IPAddressAuthorisation.IsAuthorised(callingIPAddress))
            {
                throw new SecurityException("Unauthorised calling IP");
            }

            return null;
        }

        /// <summary>
        /// Called after the operation has returned but before the reply message is sent.
        /// </summary>
        /// <param name="reply">The reply message. This value is null if the operation is one way.</param>
        /// <param name="correlationState">The correlation object returned from the <see cref="M:System.ServiceModel.Dispatcher.IDispatchMessageInspector.AfterReceiveRequest(System.ServiceModel.Channels.Message@,System.ServiceModel.IClientChannel,System.ServiceModel.InstanceContext)"/> method.</param>
        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            return;
        }
    }
}
